package demo1;


import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: 实现查询的通用封装操作
 * @author: apple
 * @date:  2022/1/9 10:34 下午
 * @version 1.0
 **/
public class PreparedStatementQueryTest {

   /*
   既然是泛型方法，要借助反射来实现，反射的源头是Class
    */
    public <T> T getInstance(Class<T> clazz, String sql , Object...params) throws SQLException, IOException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtil.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                if (params[i] == null) {
                    continue;
                }
                preparedStatement.setObject(i+1,params[i]);
            }
            resultSet = preparedStatement.executeQuery();
            // 拿到结果集的元数据，用于获取表的列数等信息
            final ResultSetMetaData metaData = resultSet.getMetaData();
            final int columnCount = metaData.getColumnCount();
            if (resultSet.next()) {
                // 泛型的实例只能通过运行时类来创建,创建实例，类型为T类型（泛型）
                final T t = clazz.newInstance();
                System.out.println(t.getClass());
                for (int i = 0; i < columnCount; i++) {
                    final Object columnValue = resultSet.getObject(i + 1);
                    // 获取列的列名，但获取不了列的别名
                    final String columnName = metaData.getColumnName(i + 1);
                    // 调用student对象的columnName列，设置为columnValue
                    final Field f1 = clazz.getDeclaredField(columnName);
                    f1.setAccessible(true);
                    f1.set(t,columnValue);
                }
                return t;
            }

        } finally {
            JDBCUtil.closeConnection(connection,preparedStatement,resultSet);
        }
        return null;
    }


    public <T> List<T> getForList(Class<T> clazz, String sql , Object...params) throws SQLException, IOException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtil.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                if (params[i] == null) {
                    continue;
                }
                preparedStatement.setObject(i+1,params[i]);
            }
            resultSet = preparedStatement.executeQuery();
            // 拿到结果集的元数据，用于获取表的列数等信息
            final ResultSetMetaData metaData = resultSet.getMetaData();
            final int columnCount = metaData.getColumnCount();
            List<T> list = new ArrayList<>();
            while (resultSet.next()) {
                // 泛型的实例只能通过运行时类来创建,创建实例，类型为T类型（泛型）
                final T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    final Object columnValue = resultSet.getObject(i + 1);
                    // 获取列的列名，但获取不了列的别名
                    final String columnName = metaData.getColumnName(i + 1);
                    // 调用student对象的columnName列，设置为columnValue
                    final Field f1 = clazz.getDeclaredField(columnName);
                    f1.setAccessible(true);
                    f1.set(t,columnValue);
                }
                list.add(t);
            }
            return list;
        } finally {
            JDBCUtil.closeConnection(connection,preparedStatement,resultSet);
        }
    }

    @Test
    public void test1() throws InstantiationException, IllegalAccessException, SQLException, IOException, NoSuchFieldException {
        String sql = "select * from student";
        final Student instance = getInstance(Student.class, sql);
        System.out.println(instance);

        final List<Student> forList = getForList(Student.class, sql);
        for (Student stu : forList) {
            System.out.println(stu);
        }


    }
}
